package aom.ju.ss.utils.http;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.text.TextUtils;

import androidx.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.juquan.lpUtils.http.TrustAllCerts;


import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import aom.ju.ss.BuildConfig;
import aom.ju.ss.R;
import aom.ju.ss.lpInterface.MyHttpCallBack;
import aom.ju.ss.lpInterface.MyHttpCallBackInDownLoad;
import aom.ju.ss.mode.LpKey;
import aom.ju.ss.mode.PublicMode;
import aom.ju.ss.mode.UserInfo;
import aom.ju.ss.utils.BaseApplication;
import aom.ju.ss.utils.LogUtils;
import aom.ju.ss.utils.SpUtils;
import aom.ju.ss.view.base.LoadingDialog;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import static aom.ju.ss.utils.RootUtilsKt.show;
import static com.tencent.mm.opensdk.constants.ConstantsAPI.TOKEN;


/**
 * Created by 10237 on 2016/11/11.
 * <p>
 * 网络请求
 */

public class OKHttpUtils {
    private final int GET = 0;
    private final int POST = 1;
    private final int UP_FILE = 3;
    private final int DOWN = 4;
    private final int PUT = 5;
    private final int PUT_WODN = 6;
    private final int DEL = 7;

    private OkHttpClient okHttpClient;
    private Request request;
    private String ApiUri;
    private final int ok = 1, error = 2, downOk = 3, downErr = 4, loginOutTime = 10;
    private String[] key, value;
    private String StringJson = BaseApplication.getInstance().getString(R.string.qqsb);
    private String errorString = BaseApplication.getInstance().getString(R.string.qqsb);
    private MyHttpCallBack callBack;
    private MyHttpCallBackInDownLoad callBackInDownLoad;
    private long time;
    private Call call;
    private File[] file;
    private File DownFile;
    private long UserPercentage = 0;
    private String httpType;
    private String loadingStr = BaseApplication.getInstance().getString(R.string.sjhqz);
    private String fakeData;
    private Activity activity;
    private boolean isForm = true;
    private LoadingDialog dialog;
    private String json;
    public static final String FileNUll = "FileNUll";
    public PublicMode publicMode;

    public OKHttpUtils(@Nullable Activity activity) {
        this.activity = activity;
        try {

            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                dialog = new LoadingDialog(activity);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        newHttpUtil(20);

    }

    public OKHttpUtils(@Nullable Activity activity, Integer loginOutTime) {
        this.activity = activity;

        newHttpUtil(loginOutTime);

    }

    public OKHttpUtils(@Nullable Activity activity, boolean isShowLoading) {
        this.activity = activity;
        try {
            if (isShowLoading && activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                dialog = new LoadingDialog(activity);
            }
        } catch (Exception ignored) {

        }

        newHttpUtil(20);

    }

    public OKHttpUtils(@Nullable Activity activity, int time) {
        this.activity = activity;
        try {
            if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
                dialog = new LoadingDialog(activity);
            }
        } catch (Exception e) {

        }
        newHttpUtil(time);

    }


    private void newHttpUtil(int s) {
        okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(1000 * s, TimeUnit.SECONDS)//连接超时
                .readTimeout(1000 * s, TimeUnit.SECONDS) //读取超时
                .writeTimeout(1000 * s, TimeUnit.SECONDS) //写超时
                .sslSocketFactory(createSSLSocketFactory(), new X509TrustManagers())
                .hostnameVerifier(new HostnameVerifiers())
                .build();
        time = System.currentTimeMillis();
    }

    public OkHttpClient get() {
        return okHttpClient;
    }


    public OKHttpUtils SetApiUrl(String uri) {
        if (BuildConfig.DEBUG) {
            ApiUri = LP_API.INSTANCE.getAPI_BASE_URL() + uri;
        } else {
            ApiUri = LP_API.INSTANCE.getAPI_BASE_URL() + uri;
        }


        LogUtils.e("ApiUri" + ApiUri);
        httpType = uri;
        return this;
    }

    /**
     * 传外部api
     *
     * @param uri    服务器前缀
     * @param apiUri api名称
     * @return this
     */
    public OKHttpUtils SetApiUrl(String uri, String apiUri) {
        httpType = apiUri;
        ApiUri = uri + apiUri;
        return this;
    }

    public OKHttpUtils isPubParam(boolean isPubParams) {
        return this;
    }

    public OKHttpUtils SetKey(String... key) {
        this.key = key;
        return this;
    }

    /**
     * 是否表单提交 默认json提交
     *
     * @param isForm
     * @return
     */
    public OKHttpUtils isForm(boolean isForm) {
        this.isForm = isForm;
        return this;
    }

    /**
     * 假数据
     *
     * @param FakeData
     * @return
     */
    public OKHttpUtils FakeData(String FakeData) {
        this.fakeData = FakeData;
        return this;
    }

    /**
     * 提交的json
     *
     * @param json
     * @return
     */
    public OKHttpUtils SetJson(String json) {
        LogUtils.e(json);
        this.json = json;
        return this;
    }

    public OKHttpUtils SetValue(String... value) {
        this.value = value;
        return this;
    }


    public void GET(MyHttpCallBack callBack) {
        this.callBack = callBack;

        try {
            readyParameter(GET);
        } catch (Exception e) {

            dismiss();
            errorFun();
            LogUtils.e(e.getMessage());
        }

    }

    private void dismiss() {
        try {
            if (dialog != null) {
                dialog.dismiss();
            }
        } catch (Exception e) {

        }

    }

    public void DOWN(MyHttpCallBackInDownLoad callBackInDownLoad) {
        this.callBackInDownLoad = callBackInDownLoad;
        //文件后缀名

        try {
            readyParameter(DOWN);
        } catch (Exception e) {
            dismiss();
            errorFun();
            LogUtils.e(e.getMessage());
        }
    }

    public void PutAndDown(MyHttpCallBackInDownLoad callBackInDownLoad) {
        this.callBackInDownLoad = callBackInDownLoad;
        //文件后缀名

        try {
            readyParameter(PUT_WODN);
        } catch (Exception e) {
            dismiss();
            errorFun();
            LogUtils.e(e.getMessage());
        }
    }


    public void POST(MyHttpCallBack callBack) {
        this.callBack = callBack;

        try {
            readyParameter(POST);
        } catch (Exception ignored) {
            dismiss();
            errorFun();
            LogUtils.e(ignored.getMessage());
        }
    }

    public void DEl(MyHttpCallBack callBack) {
        this.callBack = callBack;

        try {
            readyParameter(DEL);
        } catch (Exception ignored) {
            dismiss();
            errorFun();
            LogUtils.e(ignored.getMessage());
        }
    }

    public void PUT(MyHttpCallBack callBack) {
        this.callBack = callBack;

        try {
            readyParameter(PUT);
        } catch (Exception ignored) {
            dismiss();
            errorFun();
            LogUtils.e(ignored.getMessage());
        }
    }

    private void errorFun() {
        if (callBack != null) {
            Result(error);
        } else if (callBackInDownLoad != null) {
            Result(downErr);
        }
    }

    public void UpFile(MyHttpCallBack callBack) {
        this.callBack = callBack;
        if (file.length == 0 || file[0] == null || !file[0].isFile()) {
            callBack.error(FileNUll, "", httpType);
            return;
        }

        try {
            readyParameter(UP_FILE);
        } catch (Exception e) {
            dismiss();
            errorFun();
            LogUtils.e(e.getMessage());
        }

    }


    public OKHttpUtils setFile(File... mFile) {
        file = mFile;
        return this;
    }

    public OKHttpUtils setLoadingStr(String str) {
        loadingStr = str;
        return this;
    }

    public OKHttpUtils setDownFile(File mFile) {
        DownFile = mFile;
        return this;
    }

    /**
     * 关闭请求
     */
    public OKHttpUtils ClearAll() {
        try {
            call.cancel();
        } catch (Exception ignored) {
        }

        return this;
    }


    /**
     * 请求主体
     */


    private void Request(final int type) {
        if (activity == null || activity.isDestroyed()) {
            return;
        }
        if (!NetWorkUtils.INSTANCE.isNetworkConnected()) {
            errorString = BaseApplication.getInstance().getString(R.string.wlwlj);
            show("未连接网络");
            dismiss();
            if (callBack != null) {
                Result(error);
            } else if (callBackInDownLoad != null) {
                Result(downErr);
            }
            return;
        }

        call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                activity.runOnUiThread(() -> dismiss());
                if (activity == null || activity.isDestroyed()) {
                    return;
                }

                LogUtils.e(ApiUri + "onFailure" + e.getMessage() + "耗时=" + (System.currentTimeMillis() - time) + "");
                if (callBack != null) {
                    if (ApiUri.contains("http://file.cooscene.com")) {
                        errorString = "img401";
                    }
                    Result(error);
                } else if (callBackInDownLoad != null) {
                    Result(downErr);
                }


            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                dismiss();


                LogUtils.e(ApiUri + "耗时=" + (System.currentTimeMillis() - time));
                if (activity == null || activity.isDestroyed()) {
                    return;
                }
                int httpCode = response.code();

                if (httpCode == 500 || httpCode == 404) {
                    String js = "";
                    try {
                        js = response.body().string();

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    errorString = "网络不太好请稍后再试" + httpCode;

                    LogUtils.e("\nonResponse: \n" + js);

                    errorFun();
                    return;
                }

                LogUtils.e(httpCode + "httpCode");
                try {
                    if (type != PUT_WODN && type != DOWN) {
                        StringJson = response.body().string();
                        if (StringJson.contains("<head><title>")) {
                            errorFun();
                            return;
                        }
                        httpCode = response.code();

                        LogUtils.e("\n" + "返回的数据" + httpCode + "<=code" + StringJson + "\n");
                    }
                } catch (IOException e) {

                    LogUtils.e(e.getMessage());
                    e.printStackTrace();
                }


                try {
                    switch (type) {
                        case PUT_WODN:
                        case DOWN:
                            InputStream is = null;
                            byte[] buf = new byte[2048];
                            int len;
                            FileOutputStream fos = null;
                            try {
                                long total = response.body().contentLength();
                                long current = 0;
                                long old = 0;
                                is = response.body().byteStream();
                                fos = new FileOutputStream(DownFile);
                                int Percentile = (int) (total / 100);
                                while ((len = is.read(buf)) != -1) {
                                    current += len;
                                    fos.write(buf, 0, len);
                                    if (Percentile != 0) {
                                        UserPercentage = (current / Percentile);
                                    }

                                    if (old != UserPercentage) {


                                        LogUtils.e(UserPercentage + "%");
                                        callBackInDownLoad.downloadUpProgress(UserPercentage, httpType);

                                        old = UserPercentage;

                                        DialogStrs(UserPercentage + "%");
                                    }

                                }
                                dismiss();
                                StringJson = DownFile.getPath();
                                Result(downOk);
                                LogUtils.e(StringJson);
                            } catch (Exception e) {

                                LogUtils.e(e.getMessage() + "e.getMessage()");
                            } finally {
                                try {
                                    is.close();
                                } catch (Exception e) {

                                    LogUtils.e(e.getMessage() + "e.getMessage()");
                                }
                                try {
                                    fos.close();
                                } catch (Exception e) {

                                    LogUtils.e(e.getMessage() + "e.getMessage()");
                                }
                            }
                            break;
                        case POST:
                        case GET:
                        case PUT:
                        case DEL:
                            publicMode = new Gson().fromJson(StringJson, PublicMode.class);

                            activity.runOnUiThread(() -> {
                                dismiss();
                                if (publicMode != null) {
                                    switch (publicMode.getCode()) {
                                        case 0:
                                            Result(ok);
                                            break;
                                        case 401:
                                            Result(loginOutTime);
                                            break;
                                        default:
                                            errorString = publicMode.getMsg();
                                            Result(error);
                                            break;
                                    }

                                }


                            });

                            break;

                        case UP_FILE:
                            activity.runOnUiThread(() -> {
                                try {
                                    dismiss();
                                    LogUtils.e(ApiUri + "返回的数据=" + StringJson);
                                    PublicMode po = new Gson().fromJson(StringJson, PublicMode.class);
                                    if (po != null
                                            && po.getCode() != 200) {// ok
                                        Result(ok);
                                    } else {// error
                                        if (po != null &&
                                                po.getMsg() != null) {
                                            StringJson = po.getMsg();
                                            errorString = po.getMsg();
                                        }
                                        Result(error);
                                    }
                                } catch (Exception e) {
                                    errorString = e.getMessage();
                                    Result(error);
                                    e.printStackTrace();
                                }
                            });


                            break;
                    }

                } catch (Exception e) {
                    Result(error);
                    LogUtils.e(e.getMessage());
                }

            }
        });
    }

    /**
     * GET 方式 拼接数据
     */
    private String ParamString(String[] key, String[] value) {

        if (json != null) {
            return json;
        }

        StringBuilder mParamString = new StringBuilder();
        if (key == null || key.length == 0) {
            return mParamString.toString();
        } else {
            for (int i = 0; i < key.length; i++) {
                if (!TextUtils.isEmpty(key[i])) {
                    if (value[i] == null) {
                        value[i] = "";
                    }
                    if (i == 0) {
                        mParamString.append("?").append(key[i]).append("=").append(value[i]);
                    } else {
                        mParamString.append("&").append(key[i]).append("=").append(value[i]);
                    }

                }

            }
        }


        LogUtils.e(mParamString.toString() + "e.mParamString.toString()()");
        return mParamString.toString();

    }


    /**
     * POST/PUT 数据 json方式
     */
    private RequestBody mRequestBodyJson(String[] key, String[] value) {
        if (json != null) {
            return RequestBody.create(MediaType.parse("application/json;charset=utf-8"), json);
        }

        if (isForm) {
            return mRequestBodyData(key, value);
        }

        JsonObject json = new JsonObject();
        if (key != null) {
            for (int i = 0; i < key.length; i++) {
                if (!TextUtils.isEmpty(key[i])) {
                    if (TextUtils.isEmpty(value[i])) {
                        value[i] = "";
                    }
                    json.addProperty(key[i], value[i]);
                }
            }
        }
        LogUtils.e("mRequestBodyJson:" + json.toString());
        return RequestBody.create(MediaType.parse("application/json;charset=utf-8"), json.toString());

    }


    /**
     * POST/PUT 数据 表单方式
     *
     * @param key
     * @param value
     */
    private RequestBody mRequestBodyData(String[] key, String[] value) {
        FormBody.Builder builder = new FormBody.Builder();
        if (key != null) for (int i = 0; i < key.length; i++)
            if (!TextUtils.isEmpty(key[i])) {
                if (TextUtils.isEmpty(value[i])) {
                    value[i] = "";
                }

                LogUtils.e("\nmRequestBodyData:" + key[i] + "___" + value[i]);
                builder.add(key[i], value[i]);
            }
        return builder.build();

    }

    private void readyParameter(int type) {
        if (LpKey.INSTANCE.getIsFakeData() && callBack != null && fakeData != null) {
            if (callBack != null) {
                callBack.ok(fakeData, httpType);
            }
            dismiss();
            return;
        }

        /*
         * online 准备Request 数据
         *
         * @param type
         */
        if (activity == null || activity.isDestroyed()) {
            return;
        }
        Request.Builder builder = new Request.Builder();


        LogUtils.e("token:" + SpUtils.getString(LpKey.INSTANCE.getTOKEN()));
        if (!TextUtils.isEmpty(SpUtils.getString(LpKey.INSTANCE.getTOKEN()))) {
            builder.addHeader("token", SpUtils.getString(LpKey.INSTANCE.getTOKEN()));
        }
// SpUtils.getString("CHANNEL") 渠道号
        builder.addHeader("client-id", SpUtils.getString("CHANNEL").equals("") ? "1" : SpUtils.getString("CHANNEL"));
        builder.addHeader("platform", "android");
        builder.addHeader("version", BaseApplication.getInstance().getAppVersion() + "");
        switch (type) {
            case GET:
                builder.url(ApiUri + ParamString(key, value));

                LogUtils.e(ApiUri + "接口的GET提交参数：" + ParamString(key, value));
                break;
            case POST:
                builder.url(ApiUri)
                        .post(mRequestBodyJson(key, value));
                break;
            case PUT:
            case PUT_WODN:
                builder.url(ApiUri)
                        .put(mRequestBodyJson(key, value));

                break;
            case DOWN:
                builder.url(ApiUri);
                break;
            case DEL:
                builder.url(ApiUri)
                        .delete(mRequestBodyData(key, value));
                break;
            case UP_FILE:
                MultipartBody.Builder upFileBody = new MultipartBody.Builder();
                upFileBody.setType(MultipartBody.FORM);

                if (file != null && file.length > 0) {
                    for (File file : file) {
                        MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
//                            application/x-www-form-urlencoded
                        upFileBody.addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file));

                    }
                }


                if (key != null && key.length != 0) {
                    for (int i = 0; i < key.length; i++) {
                        upFileBody.addFormDataPart(key[i], value[i]);
                    }
                }

                MultipartBody multipartBody = upFileBody.build();

                builder.url(ApiUri)
                        .post(multipartBody);

                break;
        }

        request = builder.build();

        Request(type);

        if (type != DOWN && type != PUT_WODN && loadingStr != null) {
            DialogStrs(loadingStr);
        }

    }

    private void DialogStrs(String s) {
        try {
            if (activity != null && !activity.isDestroyed()) {
                activity.runOnUiThread(() -> {

                    if (dialog != null) {
                        dialog.setTvStr(s);
                    }
                });
            }
        } catch (Exception ex) {

        }


    }

    /**
     * 返回结果
     *
     * @param mode
     */
    private void Result(int mode) {
//        try {
        if (activity == null || activity.isDestroyed()) {
            return;
        }
        activity.runOnUiThread(() -> {

            switch (mode) {
                case ok:
                    callBack.ok(StringJson, httpType);
                    break;
                case error:
                    callBack.error(errorString, StringJson, httpType);
                    break;
                case downOk:
                    callBackInDownLoad.ok(StringJson, httpType);
                    break;
                case downErr:
                    callBackInDownLoad.error(errorString, httpType);
                    break;
                case loginOutTime:
//                    UserInfoUtils.DelDataAndOutLogin(activity);
                    show("登录超时！");
                    break;
            }

        });
    }


    /**
     * https 配置
     */
    private SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());

            ssfFactory = sc.getSocketFactory();

        } catch (Exception ignored) {
        }

        return ssfFactory;
    }

    /**
     * https 配置
     */
    private static class X509TrustManagers implements X509TrustManager {

        @SuppressLint("TrustAllX509TrustManager")
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {

        }

        @SuppressLint("TrustAllX509TrustManager")
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    /**
     * https 配置
     */
    private static class HostnameVerifiers implements HostnameVerifier {
        @SuppressLint("BadHostnameVerifier")
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}


